package com.sparrow.datasource;

import java.io.FileInputStream;
import java.io.PrintWriter;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.sql.Connection;
import javax.sql.DataSource;
import com.sparrow.core.Log;
import com.sparrow.utils.FileUtil;
import com.sparrow.utils.StringUtil;

/**
 * Mysql数据库链接池
 * 
 * @author zhanglizhi
 * @date Apr 9, 20116:36:37 PM
 * @version 1.0
 */
public class ConnectionPool implements DataSource {

	private static Map<String, ConnectionPool> poolMap = new ConcurrentHashMap<String, ConnectionPool>();
	private int loginTimeout = 0;
	/**
	 * 数据池数组对象
	 * 
	 * connectionPool加最后一次使用时间
	 */
	public Vector<Connection> pool;

	public Map<Connection, Long> usedPool;

	private String poolName;

	/**
	 * MYSQL链接URL
	 */
	private String url;

	/**
	 * 链接用户名
	 */
	private String username;

	/**
	 * 链接密码
	 */
	private String password;

	/**
	 * 驱动程序名称
	 */
	private String driverClassName;

	/**
	 * 链接池初始大小
	 */
	private int poolSize = 1;

	private static ConnectionPool instance = new ConnectionPool();;

	/**
	 * 单子构造
	 */
	private ConnectionPool() {
		init();
	}

	private ConnectionPool(String poolName) {
		this.poolName = poolName;
		this.init();
	}

	/**
	 * 初始化数据库链接池
	 */
	private void init() {
		pool = new Vector<Connection>(poolSize);
		this.usedPool = new ConcurrentHashMap<Connection, Long>();
		readConfig();
		Connection conn = null;
		for (int i = 0; i < this.poolSize; i++) {
			try {
				Class.forName(this.driverClassName);
				// 新对象
				conn = new ProxyConnection(url, username, password, pool,
						usedPool);
				pool.add(conn);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 关闭连接池中的所有数据库连接
	 */
	public synchronized void closePool() {
		for (int i = 0; i < pool.size(); i++) {
			try {
				(pool.get(i)).close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			pool.remove(i);
		}
	}

	/**
	 * 获取链接池对象
	 * 
	 * @author zhanglizhi
	 * @date Apr 9, 2011
	 * @version 1.0
	 * @return
	 */
	public static ConnectionPool getInstance() {
		return instance;
	}

	public synchronized static ConnectionPool getInstance(Enum<?> pn) {
		String poolName = pn.toString().toLowerCase();
		if (poolMap.containsKey(poolName)) {
			return poolMap.get(poolName);
		} else {
			ConnectionPool pool = new ConnectionPool(poolName);
			poolMap.put(poolName, pool);
			return pool;
		}
	}

	/**
	 * 从链接池中获取链接对象
	 * 
	 * @author zhanglizhi
	 * @date Apr 9, 2011
	 * @version 1.0
	 * @param autoCommit
	 * @return Connection
	 * @throws SQLException
	 */
	public synchronized Connection getConnection() {
		Connection conn =null;
		
		if (pool.size() > 0) {// 如果池中存在链接对象则从池获取
			conn = pool.get(0);
			pool.remove(conn);
			try {
				if (conn == null || conn.isClosed()) {
					conn = this.getConnection();
				} else {
					System.out.println("从池中获取...");
					this.usedPool.put(conn, System.currentTimeMillis());
				}
			} catch (SQLException e) {
				Log.getInstance().error(e);
			}
		} else {// 如果池中不存在
			Integer timeoutConnectionCount = 0;
			// 判断是否已经超过最大连接时间
			if (this.usedPool.size() >= this.poolSize) {
				Iterator<Connection> it = this.usedPool.keySet().iterator();
				while (it.hasNext()) {
					Connection c = it.next();
					if ((System.currentTimeMillis() - this.usedPool.get(c)) / 1000 / 60d > this
							.getLoginTimeout()) {
						timeoutConnectionCount++;
						this.pool.add(c);
						this.usedPool.remove(c);
					}
				}
			}
			// 没有超时的连接
			if (timeoutConnectionCount == 0) {
				// 此处不要放入池中.release时即放回池中
				try {
					Class.forName(this.driverClassName);
					conn = DriverManager.getConnection(this.url, this.username,
							this.password);
					System.out.println("新建连接...");
					this.usedPool.put(conn, System.currentTimeMillis());
				} catch (Exception e) {
					Log.getInstance().error(e);
				}
			}
			// 有超时的连接
			else {
				System.out.println("释放了" + timeoutConnectionCount + "个连接");
				conn = this.getConnection();
			}
		}
		return conn;
	}

	/**
	 * 读取链接池配置文件
	 * 
	 * @author zhanglizhi
	 * @date Apr 9, 2011
	 * @version 1.0
	 */
	private void readConfig() {
		try {
			Properties props = new Properties();
			String path = FileUtil.getInstance().getClassesPhysicPath();
			if (StringUtil.isNullOrEmpty(this.poolName)) {
				this.poolName = "dbpool";
			}
			props.load(new FileInputStream(path + "/" + this.poolName
					+ ".properties"));
			this.driverClassName = props.getProperty("driverClassName");
			this.username = props.getProperty("username");
			this.password = props.getProperty("password");
			this.url = props.getProperty("url");
			this.poolSize = Integer.parseInt(props.getProperty("poolSize"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public PrintWriter getLogWriter() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int getLoginTimeout() {
		return this.loginTimeout;
	}

	@Override
	public void setLogWriter(PrintWriter arg0) throws SQLException {
		// TODO Auto-generated method stub

	}

	@Override
	public void setLoginTimeout(int arg0) {
		this.loginTimeout = arg0;
	}

	@Override
	public boolean isWrapperFor(Class<?> arg0) throws SQLException {
		throw new SQLException("isWrapperFor(Class<?> arg0) method");

	}

	@Override
	public <T> T unwrap(Class<T> arg0) throws SQLException {
		throw new SQLException("not support unwrap(Class<T> arg0) method");

	}

	@Override
	public Connection getConnection(String username, String password)
			throws SQLException {
		throw new SQLException(
				"not support getConnection(String username, String password) method");
	}
}
